﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Resources;
using System.Windows;
using System.Windows.Markup;

namespace Foundation.MarkupExtensions
{
    public class Localizing : MarkupExtension
    {
        public delegate string ValueTransformer(string value, object targetObject = null, object targetProperty = null);   
        public static readonly List<ResourceManager> Managers = new List<ResourceManager>();
        public static readonly List<object> ExcludedProperties = new List<object>(); 
        public static readonly object TailProperty = typeof (Localizing).GetProperty("Tail");       
        public static event Action LocalizationChanged = () => Localizings.ForEach(l => l.TargetUpdated()); 
        public static ValueTransformer DefaultTransformer;
        private static readonly List<Localizing> Localizings = new List<Localizing>();   
 
        public Localizing(string key)
        {
            Key = key;
            Localizings.Add(this);
        }

        [ConstructorArgument("Key")]
        public string Key { get; set; }
        public string StringFormat { get; set; }
        public ValueTransformer Transformer { get; set; }
        public Localizing Tail { get; set; }
        public event Action TargetUpdated = () => { };
        protected WeakReference TargetObject;

        public static void RaiseLocalizingChanged()
        {
            DisposeUselessLocalizings();
            LocalizationChanged();
        }

        public static void DisposeUselessLocalizings()
        {
            Localizings.RemoveAll(l => l.TargetObject == null || !l.TargetObject.IsAlive);
            GC.Collect();
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var service = (IProvideValueTarget) serviceProvider.GetService(typeof (IProvideValueTarget));
            var targetObject = service.TargetObject;
            var targetProperty = service.TargetProperty;
            if (Equals(targetProperty, TailProperty) || ExcludedProperties.Contains(targetProperty))
                return this;

            var dependancyObject = targetObject as DependencyObject;
            var dependancyProperty = targetProperty as DependencyProperty;
            if (dependancyProperty != null)
            {
                if (dependancyObject == null)
                    return this;

                TargetObject = new WeakReference(dependancyObject);
                TargetUpdated = () =>
                    {    
                        var target = TargetObject.Target as DependencyObject;
                        if (target == null) return;
                        var value = ProvideValue(Key, StringFormat, Transformer, Tail, target, targetProperty);
                        target.SetValue(dependancyProperty, value);
                    };
            }

            return ProvideValue(Key, StringFormat, Transformer, Tail, targetObject, targetProperty);
        }

        public static string ProvideValue(
            string key, string stringFormat = null, ValueTransformer transformer = null,
            Localizing tail = null, object tatgetObject = null, object tatgerProperty = null)
        {
            if (key == null) return null;
            var value = Managers.Select(m => m.GetString(key)).LastOrDefault(v => v != null) ?? "<" + key + ">";
            if (stringFormat != null) value = string.Format(stringFormat, value);
            transformer = transformer ?? DefaultTransformer;
            if (transformer != null) value = transformer(value, tatgetObject, tatgerProperty);
            if (tail != null)
                value += ProvideValue(tail.Key, tail.StringFormat, tail.Transformer, tail.Tail, null, tatgerProperty);
            return value;
        }
    }
}